<?php

abstract class JCAT_DBIdentity
	implements JCAT_IIdentity
{
	/**
	 * 
	 *@access public 
	 *@param $aDBDocument									JCAT_IDBDocument		文档名称 
	 *@param $sAuthIDColumnName							string					认证ID字段名 
	 *@param $sAuthUserColumnName							string					认证用户名字段名 
	 *@param $sAuthPasswordColumnName					string					认证密码字段名 
	 *@return void 
	 */
	public function JCAT_DBIdentity (
					JCAT_IDBDocument $aDBDocument
					, $sAuthUserColumnName
					, $sAuthPasswordColumnName )
	{
		// parent::__construct($sName, $DBTable, $sAuthIDColumnName, $InfoClmList, $aDB);

		// 设置用户、密码 字段
		$this->sAuthUserColumnName = $aDBDocument->GetStdColumnName($sAuthUserColumnName) ;
		$this->sAuthPasswordColumnName = $aDBDocument->GetStdColumnName($sAuthPasswordColumnName) ;

		$this->aDBDocument = $aDBDocument ;

		// 初始化 对象
		$this-> _InitializeIdentityObject() ;
	}
	
	/**
	 * 返回 数据库文档
	 *
	 * @access	public
	 * @return	JCAT_DBDocument
	 */
	public function GetDBDocument()
	{
		return $this->aDBDocument ;
	}
	
	/**
	 * 取得 用户 的 UserID
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetUserId()
	{
		return $this->aDBDocument->GetPrimaryKeyValue() ;
	}
	
	/**
	 * 取得身份类型
	 *
	 * @access	public
	 * @return	string
	 */
	public function GetIdentityClass()
	{
		return get_class($this) ;
	}
	
	/**
	 * 初始化对象，独立于构造函数，以便构造函数和 __wakeup() 均能访问
	 * 
	 * @access	protected
	 * @return	void
	 */
	protected function _InitializeIdentityObject()
	{
		// 创建默认的 会话对象
		$this->aSession = JCAT_Session::StartSession() ;
	}
	
	/**
	 * 主要用于会话恢复时
	 * 
	 * @access	public
	 * @return	void
	 */
	public function __wakeup()
	{
		// 初始化 对象
		$this->_InitializeIdentityObject() ;
		
		// 注册到 身份中心
		if( $this->IsLogined() )
		{
			JCAT_IdentityManager::IdentityLogin($this) ;
		}
	}
	
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @return	void
	 */
	public function __sleep()
	{
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('aDBDocument',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('bLogined',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sAuthUserColumnName',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sAuthPasswordColumnName',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sCreateTimeColumnName',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sLastLoginTimeColumnName',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sLastLoginIPColumnName',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sActiveTimeColumnName',__CLASS__) ;
		$arrParentPropertys[] = JCAT_Package::MakePrivatePropertyNameForSerialize('sPurviewColumnName',__CLASS__) ;
		
		return $arrParentPropertys ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return int 
	 * @see JCAT_IIdentity::Active()
	 */
	public function Active()
	{
		JCAT_ASSERT::ASSERT_NOTNULL($this->sActiveTimeColumnName,JCAT_Language::SentenceEx('尚未设置相关字段，请先调用 SetActiveTimeColumnName() 方法','JCAT',null));
		JCAT_ASSERT::ASSERT_($this->aDBDocument->IsDataExists($this->sActiveTimeColumnName),JCAT_Language::SentenceEx('字段表中不存在字段“%s”；请在构造函数中将此字段加入到字段表中。','JCAT',null,$this->sActiveTimeColumnName)) ;
		
		// 更新数据
		$nActiveTime = time() ;
		$this->aDBDocument->Set($this->sActiveTimeColumnName,$nActiveTime) ;
		
		// 保存
		if( $this->ModifyUserInfomation( array($this->sActiveTimeColumnName)) )
		{
			return $nActiveTime ;
		}
		
		else
		{
			return 0 ;
		}
	}
	
	/**
	 * 
	 * @access public 
	 * @return int 
	 * @see JCAT_IIdentity::SetEncryption()
	 */
	public function SetEncryption( $Encryption=JCAT_Authentication::PASSWORD_MD5 )
	{
		JCAT_ASSERT::ASSERT_ISTHESE($Encryption,array('callback','null'));
		
		$old_value = $this->Encryption ;
		$this->Encryption = $Encryption ;
		return $old_value ;
	}

	/**
	 * 
	 * @access public 
	 * @return int 
	 * @see JCAT_IIdentity::GetEncryption()
	 */
	public function GetEncryption()
	{
		return $this->Encryption ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::IsLogined()
	 */
	public function IsLogined ()
	{
		return $this->bLogined ;
	}
	
	/**
	 * 检查权限
	 * 
	 * @access	public
	 * @param	$nPurviewBit		int			权限位
	 * @param	$sPurviewName=null	string		指定权限名称
	 * @return	bool
	 */
	public function HasPurview($nPurviewBit,$sPurviewName=null)
	{
		// 指定 权限名称
		if($sPurviewName)
		{
			$nPurview = $this->aDBDocument->Get($sPurviewName) ;
			JCAT_ASSERT::ASSERT_NOTNULL($nPurview,JCAT_Language::SentenceEx('指定的权限名称：“%s”不存在（数据表中无此字段）。','JCAT',null,$sPurviewName));
		}
		
		else
		{
			$nPurview = $this->_GetSpecialData('sPurviewColumnName','SetPurviewColumnName') ;
		}
		
		return ($nPurview & $nPurviewBit) ;
	}
	
	/**
	 * 设置会话对象
	 * 
	 * @access	public
	 * @param	$aSession	JCAT_ISession	会话
	 * @return	old_value
	 * @see JCAT_IIdentity::SetSession()
	 */
	public function SetSession(JCAT_ISession $aSession)
	{		
		$old_value = $this->aSession ;
		$this->aSession = $aSession ;
		return $old_value ;
	}

	
	/**
	 * 取得会话对象
	 * 
	 * @access	public
	 * @return	JCAT_ISession
	 * @see JCAT_IIdentity::GetSession()
	 */
	public function GetSession()
	{
		return $this->aSession ;
	}
	
	/**
	 * 
	 * @access public 
	 * @param $nAuthID		int		认证用户ID 
	 * @param $sSessionKey	string	认证用户会话名 
	 * @return int 
	 * @see JCAT_IIdentity::LoadFromSession()
	 */
	public function LoadFromSession ($nAuthID, $sSessionKey)
	{
	}
	
	/**
	 * 
	 * @access public 
	 * @param $sAuthName			string	认证用户名 
	 * @param $sAuthPassword		string	认证用户密码 
	 * @param $bSendMessage=true	bool	是否发送消息
	 * @return bool 
	 * @see JCAT_IIdentity::Login()
	 */
	public function Login ( $sAuthName, $sAuthPassword, $bSendMessage=true )
	{
		$aDBFactory = $this->aDBDocument->GetDB()->GetFactory() ;
		
		// 设置条件
		$aWhere = $this->aDBDocument->GetSubSQLWhere() ;
		$aWhere->AddCondition( $aDBFactory->CreateColumn($this->sAuthUserColumnName), $sAuthName ) ;

		if( $this->aDBDocument->Load() )
		{
			// 加密函数
			$EncryptionFunction = $this->GetEncryption() ;
			
			// 使用明文密码
			if ($EncryptionFunction===JCAT_Authentication::PASSWORD_PLAIN)
			{
				$sCipherText =& $sAuthPassword ;
			}
			
			// 用过加密函数计算密文
			else 
			{
				$sCipherText = call_user_func_array($EncryptionFunction,array($sAuthPassword)) ;
			}

			// 比较密文
			if($this->GetAuthPassword() === $sCipherText)
			{
				$this->bLogined = true ;
				
				// 保存 Session
				$aSession = $this->GetSession() ;
				$aSession->SetVariable($this->GetIdentityClass(),$this) ;
				
				// 提交到身份管理器
				JCAT_IdentityManager::IdentityLogin($this) ;
				
				// 产生消息
				if($bSendMessage)
				{
					new JCAT_Message(JCAT_Language::SentenceEx('登录成功。','JCAT',null,$sAuthName),'MSGMVC_OK') ;
				}
			}
			
			else 
			{
				$this->bLogined = false ;
				
				// 产生消息
				if($bSendMessage)
				{
					new JCAT_Message(JCAT_Language::SentenceEx('密码错误，请检查输入是否正确。','JCAT',null),'MSGMVC_BAD') ;
				}				
			}
			
		}
		else
		{
			$this->bLogined = false ;
			
			// 产生消息
			if($bSendMessage)
			{
				new JCAT_Message(JCAT_Language::SentenceEx('用户名：“%s”不存在，请检查是否输入错误。','JCAT',null,$sAuthName),'MSGMVC_BAD') ;
			}
		}
				
		// 返回结果
		return $this->IsLogined() ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::Logout()
	 */
	public function Logout ()
	{
		$this->bLogined = false ;
		
		// 从 会话里面移除
		$aSession = $this->GetSession() ;
		if( $aSession->GetVariable($this->GetIdentityClass()) === $this )
		{
			$aSession->DeleteVariable($this->GetIdentityClass()) ;
		}
		
		return true ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::Register()
	 */
	public function Register ()
	{//TODO - Insert your code here
	}

	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::Unregister()
	 */
	public function Unregister ()
	{//TODO - Insert your code here
	}
	
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::ModifyUserInfomation()
	 */
	public function ModifyUserInfomation( array $arrDataNamesForModify=array() )
	{
		JCAT_ASSERT::ASSERT_( $this->aDBDocument->IsExists(), JCAT_Language::SentenceEx('用户尚未注册，无法进行用户资料修改操作','JCAT',null) ) ;
		
		// 修改指定字段
		//if( count($arrDataNamesForModify) )
		//{
		//	$this->GetDB() ;
		//}
		
		// 修改所有字段
		//else
		{
			return $this->aDBDocument->Save() ;
		}
	}
	

	/**
	 * 取回 创建日期 等特殊内容
	 * 
	 * @access	private
	 * @param	$sColumnName		string		what's this
	 * @param	$sSetMethodName		string		what's this 
	 * @return	string, int
	 */
	private function _GetSpecialData($sPropertyName,$sSetMethodName)
	{
		JCAT_ASSERT::ASSERT_( in_array($sPropertyName,array(
					'sAuthUserColumnName'
					, 'sAuthPasswordColumnName'
					, 'sCreateTimeColumnName'
					, 'sLastLoginTimeColumnName'
					, 'sLastLoginIPColumnName'
					, 'sActiveTimeColumnName'
					, 'sPurviewColumnName')), "属性：“{$sPropertyName}”不存在。" ) ;

		JCAT_ASSERT::ASSERT_NOTNULL($this->$sPropertyName,JCAT_Language::SentenceEx('请先调用方法：“%s”设置相关属性。','JCAT',null,$sSetMethodName)) ;
		JCAT_ASSERT::ASSERT_($this->aDBDocument->IsDataExists($this->$sPropertyName),JCAT_Language::SentenceEx('字段表中不存在字段“%s”；请在构造函数中将此字段加入到字段表中。','JCAT',null,$this->$sPropertyName)) ;
		
		return $this->aDBDocument->Get($this->$sPropertyName) ;		
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::GetAuthName()
	 */
	public function GetAuthName()
	{
		return $this->_GetSpecialData('sAuthUserColumnName',__CLASS__) ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::GetAuthPassword()
	 */
	public function GetAuthPassword()
	{
		return $this->_GetSpecialData('sAuthPasswordColumnName',__CLASS__) ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::GetCreateTime()
	 */
	public function GetCreateTime()
	{
		return $this->_GetSpecialData('sCreateTimeColumnName',__CLASS__) ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::GetLastLoginTime()
	 */
	public function GetLastLoginTime()
	{
		return $this->_GetSpecialData('sLastLoginTimeColumnName',__CLASS__) ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::GetLastLoginIP()
	 */
	public function GetLastLoginIP()
	{
		return $this->_GetSpecialData('sLastLoginIPColumnName',__CLASS__) ;
	}
	
	/**
	 * 
	 * @access public 
	 * @return bool 
	 * @see JCAT_IIdentity::GetActiveTime()
	 */
	public function GetActiveTime()
	{
		return $this->_GetSpecialData('sActiveTimeColumnName',__CLASS__) ;
	}
	
	
	
	private function _SetSameColumnName($sPropertyName,& $sValue)
	{
		JCAT_ASSERT::ASSERT_( in_array($sPropertyName,array(
					'sActiveTimeColumnName'
					, 'sCreateTimeColumnName'
					, 'sLastLoginIPColumnName'
					, 'sLastLoginTimeColumnName'
					, 'sPurviewColumnName')), "属性：“{$sPropertyName}”不存在。" ) ;
		
		$sColumnName = $this->aDBDocument->GetStdColumnName($sValue) ;
		JCAT_ASSERT::ASSERT_($this->aDBDocument->IsDataExists($sColumnName),JCAT_Language::SentenceEx('字段表中不存在字段“%s”；请在构造函数中将此字段加入到字段表中。','JCAT',null,$sColumnName)) ;
		
		$old_value = $this->$sPropertyName ;
		$this->$sPropertyName = $sColumnName;
		return $old_value ;
		
	}
	
	/**
	 * 
	 * @access 	protected
	 * @param 	$sActiveTimeColumnName		string
	 * @return	old_value
	 */
	protected function SetActiveTimeColumnName ($sActiveTimeColumnName)
	{
		return $this->_SetSameColumnName('sActiveTimeColumnName',$sActiveTimeColumnName) ;
	}
	
	/**
	 * 
	 * @access 	protected
	 * @param 	$sCreateTimeColumnName		string
	 * @return	old_value
	 */
	protected function SetCreateTimeColumnName ($sCreateTimeColumnName)
	{
		return $this->_SetSameColumnName('sCreateTimeColumnName',$sCreateTimeColumnName) ;
	}
	
	/**
	 * 
	 * @access 	protected
	 * @param 	$sLastLoginIPColumnName		string
	 * @return	old_value
	 */
	protected function SetLastLoginIPColumnName ($sLastLoginIPColumnName)
	{
		return $this->_SetSameColumnName('sLastLoginIPColumnName',$sLastLoginIPColumnName) ;
	}

	/**
	 * 
	 * @access 	protected
	 * @param 	$sLastLoginTimeColumnName	string
	 * @return	old_value
	 */
	protected function SetLastLoginTimeColumnName ($sLastLoginTimeColumnName)
	{
		return $this->_SetSameColumnName('sLastLoginTimeColumnName',$sLastLoginTimeColumnName) ;
	}
	
	/**
	 * 
	 * @access 	protected
	 * @param 	$sLastLoginTimeColumnName	string
	 * @return	old_value
	 */
	protected function SetPurviewColumnName ($sPurviewColumnName)
	{
		return $this->_SetSameColumnName('sPurviewColumnName',$sPurviewColumnName) ;
	}



	// 属性 /////////////////////////////////////////////////////
	
	/**
	 * 数据库文档
	 * 
	 * @access	private
	 * @var		JCAT_IDBDocument
	 */
	private $aDBDocument ;
	
	/**
	 * 记录是否已经的登录 
	 * 
	 * @access	private
	 * @var		bool
	 */
	private $bLogined = false ;
		
	/**
	 * 认证用户名 字段名 
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sAuthUserColumnName ;
	
	/**
	 * 认证密码 字段名 
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sAuthPasswordColumnName ;

	/**
	 * 帐号创建时间 字段名 
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sCreateTimeColumnName ;

	/**
	 * 最近登录时间 字段名 
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sLastLoginTimeColumnName ;

	/**
	 * 最近登录IP 字段名 
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sLastLoginIPColumnName ;
	
	/**
	 * 最近活动时间 字段名 
	 * 
	 * @access	private
	 * @var		string
	 */
	private $sActiveTimeColumnName ;
	
	/**
	 * 权限 字段名 
	 * 
	 * @access	private
	 * @var		int
	 */
	private $sPurviewColumnName ;
	
	/**
	 * 对密码加密的 回调函数
	 * 
	 * @access	private
	 * @var		callback
	 */
	private $Encryption = JCAT_Authentication::PASSWORD_MD5 ;
	
	/**
	 * 用于保存身份的会话类类名
	 * 
	 * @access	private
	 * @var		string
	 */
	private $aSession ;
}
?>
